import { AddressLabel, ChainType } from '@/types';
import { createModuleLogger } from '@/utils/logger';
import { DatabaseService } from '@/services/database/DatabaseService';

const logger = createModuleLogger('address-label-service');

interface KnownAddress {
  address: string;
  label: string;
  type: 'exchange' | 'whale' | 'defi' | 'bridge' | 'other';
  chains: ChainType[];
}

export class AddressLabelService {
  private static instance: AddressLabelService;
  private dbService: DatabaseService;
  private knownAddresses = new Map<string, KnownAddress>();
  private addressCache = new Map<string, AddressLabel | null>();
  private cacheExpiry = 60 * 60 * 1000; // 1小时缓存

  // 知名地址数据库
  private readonly KNOWN_ADDRESSES: KnownAddress[] = [
    // 主要交易所
    {
      address: '0x28c6c06298d514db089934071355e5743bf21d60',
      label: 'Binance 14',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xdfd5293d8e347dfe59e90efd55b2956a1343963d',
      label: 'Binance Hot Wallet',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x564286362092d8e7936f0549571a803b203aaced',
      label: 'Binance',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x0681d8db095565fe8a346fa0277bffde9c0edbbf',
      label: 'Binance 7',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xfe9e8709d3215310075d67e3ed32a380ccf451c8',
      label: 'Coinbase Exchange',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xa910f92acdaf488fa6ef02174fb86208ad7722ba',
      label: 'Coinbase 4',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x503828976d22510aad0201ac7ec88293211d23da',
      label: 'Coinbase 5',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xddfabcdc4d8ffc6d5beaf154f18b778f892a0740',
      label: 'Coinbase 3',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x71660c4005ba85c37ccec55d0c4493e66fe775d3',
      label: 'Coinbase',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x267be1c1d684f78cb4f6a176c4911b741e4ffdc0',
      label: 'Kraken',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xae2fc483527b8ef99eb5d9b44875f005ba1fae13',
      label: 'Kraken 7',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x43984d578803891dfa9706bdeee6078d80cfc79e',
      label: 'Kraken 3',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x8484ef722627bf18ca5ae6bcf031c23e6e922b30',
      label: 'Huobi Global',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xdc76cd25977e0a5ae17155770273ad58648900d3',
      label: 'Huobi 16',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x6cc5f688a315f3dc28a7781717a9a798a59fda7b',
      label: 'OKEx',
      type: 'exchange',
      chains: [ChainType.ETHEREUM]
    },

    // DeFi协议
    {
      address: '0x7d2768de32b0b80b7a3454c06bdac94a69ddc7a9',
      label: 'Aave: Lending Pool V2',
      type: 'defi',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x5d3a536e4d6dbd6114cc1ead35777bab948e3643',
      label: 'Compound: cDAI Token',
      type: 'defi',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
      label: 'Uniswap: UNI Token',
      type: 'defi',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x68b3465833fb72a70ecdf485e0e4c7bd8665fc45',
      label: 'Uniswap V3: Router 2',
      type: 'defi',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xe592427a0aece92de3edee1f18e0157c05861564',
      label: 'Uniswap V3: Router',
      type: 'defi',
      chains: [ChainType.ETHEREUM]
    },

    // 跨链桥
    {
      address: '0xa0c68c638235ee32657e8f720a23cec1bfc77c77',
      label: 'Polygon: Bridge',
      type: 'bridge',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0x3ee18b2214aff97000d974cf647e7c347e8fa585',
      label: 'Wormhole: Bridge',
      type: 'bridge',
      chains: [ChainType.ETHEREUM]
    },

    // 知名鲸鱼地址
    {
      address: '0x47ac0fb4f2d84898e4d9e7b4dab3c24507a6d503',
      label: 'Binance-Peg Tokens',
      type: 'whale',
      chains: [ChainType.ETHEREUM]
    },
    {
      address: '0xbe0eb53f46cd790cd13851d5eff43d12404d33e8',
      label: 'Binance Whale',
      type: 'whale',
      chains: [ChainType.ETHEREUM]
    }
  ];

  private constructor(dbService: DatabaseService) {
    this.dbService = dbService;
    this.initializeKnownAddresses();
  }

  public static getInstance(dbService: DatabaseService): AddressLabelService {
    if (!AddressLabelService.instance) {
      AddressLabelService.instance = new AddressLabelService(dbService);
    }
    return AddressLabelService.instance;
  }

  // 初始化已知地址
  private initializeKnownAddresses(): void {
    for (const addr of this.KNOWN_ADDRESSES) {
      // 使用小写地址作为key
      const key = addr.address.toLowerCase();
      this.knownAddresses.set(key, addr);
    }
    
    logger.info(`已加载 ${this.KNOWN_ADDRESSES.length} 个知名地址标签`);
  }

  // 获取地址标签
  public async getAddressLabel(address: string, chain: ChainType): Promise<AddressLabel | null> {
    const lowerAddress = address.toLowerCase();
    const cacheKey = `${lowerAddress}_${chain}`;

    // 检查缓存
    if (this.addressCache.has(cacheKey)) {
      return this.addressCache.get(cacheKey) || null;
    }

    try {
      // 首先检查数据库中是否有标签
      const dbLabel = await this.dbService.getAddressLabel(address, chain);
      if (dbLabel) {
        this.addressCache.set(cacheKey, dbLabel);
        return dbLabel;
      }

      // 检查是否是已知地址
      const knownAddress = this.knownAddresses.get(lowerAddress);
      if (knownAddress && knownAddress.chains.includes(chain)) {
        const label: AddressLabel = {
          address: address,
          label: knownAddress.label,
          type: knownAddress.type,
          chain: chain,
          createdAt: new Date()
        };

        // 保存到数据库
        await this.dbService.saveAddressLabel(label);
        this.addressCache.set(cacheKey, label);
        
        logger.info(`识别到知名地址: ${knownAddress.label} (${address})`);
        return label;
      }

      // 检查是否是鲸鱼地址（基于历史交易量）
      const whaleLabel = await this.detectWhaleAddress(address, chain);
      if (whaleLabel) {
        await this.dbService.saveAddressLabel(whaleLabel);
        this.addressCache.set(cacheKey, whaleLabel);
        return whaleLabel;
      }

      // 没有找到标签，缓存null结果
      this.addressCache.set(cacheKey, null);
      return null;

    } catch (error) {
      logger.error(`获取地址标签失败 ${address}:`, error);
      return null;
    }
  }

  // 检测鲸鱼地址
  private async detectWhaleAddress(address: string, chain: ChainType): Promise<AddressLabel | null> {
    try {
      // 查询该地址的历史大额交易
      const transactions = await this.dbService.getTransactionsByAddress(address, chain);
      
      if (transactions.length >= 5) { // 至少5笔大额交易
        const totalValue = transactions.reduce((sum: number, tx: any) => sum + tx.valueUSD, 0);
        const avgValue = totalValue / transactions.length;

        // 如果平均交易金额超过50万美元，标记为鲸鱼
        if (avgValue > 500000) {
          const label: AddressLabel = {
            address: address,
            label: `Whale (${transactions.length}笔大额交易)`,
            type: 'whale',
            chain: chain,
            createdAt: new Date()
          };

          logger.info(`检测到鲸鱼地址: ${address}, 平均交易: $${avgValue.toLocaleString()}`);
          return label;
        }
      }

      return null;
    } catch (error) {
      logger.debug(`鲸鱼检测失败 ${address}:`, error);
      return null;
    }
  }

  // 批量标记地址
  public async labelAddress(
    address: string, 
    label: string, 
    type: 'exchange' | 'whale' | 'defi' | 'bridge' | 'other',
    chain: ChainType
  ): Promise<void> {
    const addressLabel: AddressLabel = {
      address,
      label,
      type,
      chain,
      createdAt: new Date()
    };

    await this.dbService.saveAddressLabel(addressLabel);
    
    // 更新缓存
    const cacheKey = `${address.toLowerCase()}_${chain}`;
    this.addressCache.set(cacheKey, addressLabel);
    
    logger.info(`手动标记地址: ${label} (${address})`);
  }

  // 获取地址统计
  public async getAddressStats(): Promise<{
    totalLabeled: number;
    exchanges: number;
    whales: number;
    defi: number;
    bridges: number;
    others: number;
  }> {
    // 这里应该查询数据库统计，简化实现
    return {
      totalLabeled: this.KNOWN_ADDRESSES.length,
      exchanges: this.KNOWN_ADDRESSES.filter(a => a.type === 'exchange').length,
      whales: this.KNOWN_ADDRESSES.filter(a => a.type === 'whale').length,
      defi: this.KNOWN_ADDRESSES.filter(a => a.type === 'defi').length,
      bridges: this.KNOWN_ADDRESSES.filter(a => a.type === 'bridge').length,
      others: this.KNOWN_ADDRESSES.filter(a => a.type === 'other').length
    };
  }

  // 清理过期缓存
  public clearExpiredCache(): void {
    // 简化实现，实际可以根据时间戳清理
    if (this.addressCache.size > 1000) {
      this.addressCache.clear();
      logger.debug('已清理地址标签缓存');
    }
  }

  // 检查是否是交易所地址
  public isExchangeAddress(address: string): boolean {
    const lowerAddress = address.toLowerCase();
    const known = this.knownAddresses.get(lowerAddress);
    return known?.type === 'exchange' || false;
  }

  // 检查是否是DeFi协议地址
  public isDeFiAddress(address: string): boolean {
    const lowerAddress = address.toLowerCase();
    const known = this.knownAddresses.get(lowerAddress);
    return known?.type === 'defi' || false;
  }

  // 检查是否是鲸鱼地址
  public isWhaleAddress(address: string): boolean {
    const lowerAddress = address.toLowerCase();
    const known = this.knownAddresses.get(lowerAddress);
    return known?.type === 'whale' || false;
  }

  // 获取地址简短标签（用于显示）
  public getShortLabel(address: string, chain: ChainType): string {
    const lowerAddress = address.toLowerCase();
    const known = this.knownAddresses.get(lowerAddress);
    
    if (known && known.chains.includes(chain)) {
      return known.label;
    }

    // 返回地址的缩略形式
    return `${address.substring(0, 6)}...${address.substring(address.length - 4)}`;
  }

  // 添加新的知名地址
  public addKnownAddress(knownAddress: KnownAddress): void {
    const lowerAddress = knownAddress.address.toLowerCase();
    this.knownAddresses.set(lowerAddress, knownAddress);
    logger.info(`添加知名地址: ${knownAddress.label}`);
  }
} 